package com.demo.petshop.service.impl;

import com.demo.petshop.entity.*;
import com.demo.petshop.mapper.*;
import com.demo.petshop.service.StoresService;
import com.demo.petshop.util.Result;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.mail.Store;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.sqlite.date.DateFormatUtils;
import com.demo.petshop.service.ProductsService;

import java.util.*;
import java.util.stream.Collectors;

import static com.demo.petshop.entity.table.FavoritesTableDef.FAVORITES;
import static com.demo.petshop.entity.table.OrderItemsTableDef.ORDER_ITEMS;
import static com.demo.petshop.entity.table.OrdersTableDef.ORDERS;
import static com.demo.petshop.entity.table.ProductReviewsTableDef.PRODUCT_REVIEWS;
import static com.demo.petshop.entity.table.ProductsTableDef.PRODUCTS;
import static com.demo.petshop.entity.table.StoreFollowersTableDef.STORE_FOLLOWERS;
import static com.demo.petshop.entity.table.StoreTagRelationTableDef.STORE_TAG_RELATION;
import static com.demo.petshop.entity.table.StoreTagsTableDef.STORE_TAGS;
import static com.demo.petshop.entity.table.StoresTableDef.STORES;
import static com.demo.petshop.entity.table.UsersTableDef.USERS;
import static com.demo.petshop.entity.table.StoreServicesTableDef.STORE_SERVICES;
import static com.demo.petshop.entity.table.StoreFollowersTableDef.STORE_FOLLOWERS;

/**
 *  服务层实现。
 *
 * @author lenovo
 * @since 2025-06-11
 */
@Service
public class StoresServiceImpl extends ServiceImpl<StoresMapper, Stores> implements StoresService {

    @Autowired
    private StoreTagsMapper storeTagsMapper;

    @Autowired
    private StoresMapper storesMapper;

    @Autowired
    private UsersMapper userMapper;

    @Autowired
    private ProductsMapper productMapper;

    @Autowired
    private ProductReviewsMapper productReviewsMapper;

    @Autowired
    private OrdersMapper ordersMapper;

    @Autowired
    private StoreServicesMapper storeServicesMapper;

    @Autowired
    private StoreFollowersMapper storeFollowersMapper;

    @Autowired
    private StoreTagRelationMapper storeTagRelationMapper;

    @Autowired
    private ProductsService productsService;

    @Autowired
    private FavoritesMapper favoritesMapper;
    @Autowired
    private OrderItemsMapper orderItemsMapper;



    private int getUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        return loginUser.getUser().getUserId();
    }


    @Override
    public Object getNearbyStores(String latitude, String longitude, String radius, String tagId) {
        if (latitude == null || longitude == null) {
            return Result.fail("Latitude and longitude are required");
        }

        double lat = Double.parseDouble(latitude);
        double lng = Double.parseDouble(longitude);
        double rad = radius != null ? Double.parseDouble(radius) : 5.0; // Default radius: 5km

        // Calculate the latitude and longitude ranges for the given radius
        // 1 degree of latitude = approximately 111.32 km
        // 1 degree of longitude = approximately 111.32 * cos(latitude) km
        double latRange = rad / 111.32;
        double lngRange = rad / (111.32 * Math.cos(Math.toRadians(lat)));

        // Query stores within the calculated range
        List<Stores> stores = queryChain()
                .select(STORES.ALL_COLUMNS)
                .from(STORES)
                .groupBy(STORES.STORE_ID)
                .leftJoin(STORE_TAG_RELATION).on(STORES.STORE_ID.eq(STORE_TAG_RELATION.STORE_ID))
                .where(STORE_TAG_RELATION.TAG_ID.eq(tagId).when(!"0".equals(tagId)))
                .and(STORES.LATITUDE.between(lat - latRange, lat + latRange))
                .and(STORES.LONGITUDE.between(lng - lngRange, lng + lngRange))
                .and(STORES.DELETE.eq(0))
                .list();

        // Calculate actual distance for each store and filter out those beyond the radius
        List<Map<String, Object>> result = new ArrayList<>();
        for (Stores store : stores) {
            double distance = calculateDistance(
                    lat, lng,
                    store.getLatitude(), store.getLongitude()
            );

            if (distance <= rad) {
                Map<String, Object> storeMap = convertStoreToMap(store);
                storeMap.put("distance", distance);
                result.add(storeMap);
            }
        }

        // Sort by distance
        result.sort(Comparator.comparing(store -> (Double) store.get("distance")));

        return Result.success(result);
    }

    @Override
    public Object getByTagId(Integer id) {
        return Result.success(storeTagsMapper.selectListByQuery(
                new QueryWrapper()
                        .select(STORE_TAGS.ALL_COLUMNS)
                        .from(STORES)
                        .leftJoin(STORE_TAG_RELATION).on(STORES.STORE_ID.eq(STORE_TAG_RELATION.STORE_ID))
                        .leftJoin(STORE_TAGS).on(STORE_TAG_RELATION.TAG_ID.eq(STORE_TAGS.TAG_ID))
                        .where(STORES.STORE_ID.eq(id))
                        .and(STORES.DELETE.eq(0))
        ));
    }

    @Override
    public Object getStore(Integer id) {
        return Result.success(storesMapper.selectOneById(id));
    }

    @Override
    public Object getStoresNoId() {
        return Result.success(storesMapper.selectOneByQuery(
                new QueryWrapper()
                        .select(STORES.ALL_COLUMNS)
                        .from(STORES)
                        .leftJoin(STORE_FOLLOWERS).on(STORES.STORE_ID.eq(STORE_FOLLOWERS.STORE_ID))
                        .where(STORE_FOLLOWERS.USER_ID.eq(getUserId()))
                        .and(STORES.DELETE.eq(0))
        ));
    }

    @Override
    public Object getAll(Integer tagId) {
        return Result.success(storesMapper.selectListByQuery(
                new QueryWrapper()
                        .select(STORES.ALL_COLUMNS)
                        .from(STORES)
                        .leftJoin(STORE_TAG_RELATION).on(STORES.STORE_ID.eq(STORE_TAG_RELATION.STORE_ID))
                        .leftJoin(STORE_TAGS).on(STORE_TAG_RELATION.TAG_ID.eq(STORE_TAGS.TAG_ID))
                        .where(STORE_TAG_RELATION.TAG_ID.eq(tagId).when(tagId > 0))
                        .and(STORES.DELETE.eq(0))
                        .groupBy(STORES.STORE_ID)
        ));
    }

    @Override
    public Object getReviews(Integer storeId) {
        List<ProductReviews> reviews = productReviewsMapper.selectListByQuery(
                new QueryWrapper()
                        .select(PRODUCT_REVIEWS.ALL_COLUMNS)
                        .from(PRODUCT_REVIEWS)
                        .leftJoin(PRODUCTS).on(PRODUCT_REVIEWS.PRODUCT_ID.eq(PRODUCTS.PRODUCT_ID))
                        .where(PRODUCTS.STORE_ID.eq(storeId))
                        .orderBy(PRODUCT_REVIEWS.REVIEW_ID, false)
        );
        for(ProductReviews review : reviews) {
            review.setProduct(productMapper.selectOneById(review.getProductId()));
            review.setUser(userMapper.selectOneById(review.getUserId()));
        }
        return Result.success(reviews);
    }

    @Override
    public Object reRating() {
        List<Stores> stores = storesMapper.selectAll();
        for(Stores store : stores) {
            double rating = 0;
            List<ProductReviews> reviews = productReviewsMapper.selectListByQuery(
                    new QueryWrapper()
                            .select(PRODUCT_REVIEWS.ALL_COLUMNS)
                            .from(PRODUCT_REVIEWS)
                            .leftJoin(PRODUCTS).on(PRODUCT_REVIEWS.PRODUCT_ID.eq(PRODUCTS.PRODUCT_ID))
                            .where(PRODUCTS.STORE_ID.eq(store.getStoreId()))
            );
            for(ProductReviews review : reviews) {
                rating += review.getRating();
            }
            store.setRating(rating / (reviews.isEmpty() ? 1.0 : reviews.size()));
            storesMapper.update(store);
        }
        return Result.success("success");
    }

    @Override
    public Object stats() {
        StoreStatsDTO storeStatsDTO = new StoreStatsDTO();
        storeStatsDTO.setStoreCount((int) storesMapper.selectCountByQuery(
                new QueryWrapper()
                        .select(STORES.ALL_COLUMNS)
                        .from(STORES).where(STORES.DELETE.eq(0))
        ));
        storeStatsDTO.setProductCount((int) productMapper.selectCountByQuery(
                new QueryWrapper()
                        .select(PRODUCTS.ALL_COLUMNS)
                        .from(PRODUCTS)
        ));
        storeStatsDTO.setOrderCount((int) ordersMapper.selectCountByQuery(
                new QueryWrapper()
                        .select(ORDERS.ALL_COLUMNS)
                        .from(ORDERS)
        ));
        storeStatsDTO.setMemberCount((int) userMapper.selectCountByQuery(
                new QueryWrapper()
                        .select(USERS.ALL_COLUMNS)
                        .from(USERS)
        ));
        return Result.success(storeStatsDTO);
    }

    /**
     * Convert Store object to Map
     */
    private Map<String, Object> convertStoreToMap(Stores store) {
        Map<String, Object> map = new HashMap<>();
        map.put("storeId", store.getStoreId());
        map.put("name", store.getName());
        map.put("logo", store.getLogo());
        map.put("coverImage", store.getCoverImage());
        map.put("description", store.getDescription());
        map.put("phone", store.getPhone());
        map.put("businessHours", store.getBusinessHours());
        map.put("latitude", store.getLatitude());
        map.put("longitude", store.getLongitude());
        map.put("address", store.getAddress());
        map.put("rating", store.getRating());
        map.put("reviewCount", store.getReviewCount());
        map.put("followerCount", store.getFollowerCount());
        map.put("isCertified", store.getIsCertified());
        map.put("certificationType", store.getCertificationType());
        map.put("createdAt", store.getCreatedAt());
        return map;
    }

    /**
     * Calculate distance between two points using Haversine formula
     * @return Distance in kilometers
     */
    private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        final int R = 6371; // Earth's radius in kilometers

        double latDistance = Math.toRadians(lat2 - lat1);
        double lonDistance = Math.toRadians(lon2 - lon1);

        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
                * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);

        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        return R * c;
    }

    @Override
    public Object addStore(StoresInfo storesInfo){
        Stores stores = storesInfo.getStores();
        List<StoreServices> storesServiceList = storesInfo.getStoreServicesList();
        int[] tagList = storesInfo.getTag();
        int userId = getUserId();

        //添加新商店
        Stores newStores = new Stores();
        newStores.setName(stores.getName());
        newStores.setCoverImage(stores.getCoverImage());
        newStores.setDescription(stores.getDescription());
        newStores.setPhone(stores.getPhone());
        newStores.setBusinessHours(stores.getBusinessHours());
        newStores.setLatitude(stores.getLatitude());
        newStores.setLongitude(stores.getLongitude());
        newStores.setAddress(stores.getAddress());
        newStores.setRating(0.0);
        newStores.setReviewCount(0);
        newStores.setFollowerCount(0);
        newStores.setIsCertified(1);
        newStores.setCertificationType(null);
        newStores.setLogo(null);
        newStores.setDelete(0);
        newStores.setCreatedAt(DateFormatUtils.format(new Date(), "yyyy- -dd HH:mm:ss"));
        storesMapper.insert(newStores);

        //添加新商店对应的服务
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper
                .from(STORES)
                .where(STORES.NAME.eq(stores.getName()))
                .orderBy(STORES.STORE_ID,false).limit(1);
        Stores store1 = storesMapper.selectOneByQuery(queryWrapper);
        for(StoreServices storeServices : storesServiceList){
            StoreServices newServices = new StoreServices();
            newServices.setStoreId(store1.getStoreId());
            newServices.setName(storeServices.getName());
            newServices.setDescription(storeServices.getDescription());
            newServices.setIcon(null);
            newServices.setPrice(storeServices.getPrice());
            newServices.setDuration(storeServices.getDuration());
            storeServicesMapper.insert(newServices);
        }

        //添加新店长
        StoreFollowers storeFollowers = new StoreFollowers();
        storeFollowers.setStoreId(store1.getStoreId());
        storeFollowers.setUserId(userId);
        storeFollowers.setCreatedAt(DateFormatUtils.format(new Date(), "yyyy- -dd HH:mm:ss"));
        storeFollowersMapper.insert(storeFollowers);

        //添加新标签
        for(int tag : tagList){
            StoreTagRelation storeTagRelation = new StoreTagRelation();
            storeTagRelation.setStoreId(store1.getStoreId());
            storeTagRelation.setTagId(tag);
            storeTagRelationMapper.insert(storeTagRelation);
        }

        return Result.success("创建成功");
    }

    @Override
    public Object delStore(int storeId){
        QueryWrapper serviceQW = new QueryWrapper();
        QueryWrapper followerQW = new QueryWrapper();
        QueryWrapper tagRelationQW = new QueryWrapper();
        QueryWrapper productQW = new QueryWrapper();
        QueryWrapper favoriteQW = new QueryWrapper();
        serviceQW.from(STORE_SERVICES).where(STORE_SERVICES.STORE_ID.eq(storeId));
        followerQW.from(STORE_FOLLOWERS).where(STORE_FOLLOWERS.STORE_ID.eq(storeId));
        tagRelationQW.from(STORE_TAG_RELATION).where(STORE_TAG_RELATION.STORE_ID.eq(storeId));
        productQW.from(PRODUCTS).where(PRODUCTS.STORE_ID.eq(storeId));
        favoriteQW.from(FAVORITES).where(FAVORITES.STORE_ID.eq(storeId));

        //删除商店
        Stores stores = storesMapper.selectOneById(storeId);
        stores.setDelete(1);
        storesMapper.update(stores);
        //删除商店服务
        storeServicesMapper.deleteByQuery(serviceQW);

        //删除店长
        StoreFollowers storeFollowers = storeFollowersMapper.selectOneByQuery(followerQW);
        if(storeFollowers!=null)
            storeFollowersMapper.delete(storeFollowers);

        //删除标签
        storeTagRelationMapper.deleteByQuery(tagRelationQW);

        //删除收藏
        favoritesMapper.deleteByQuery(favoriteQW);

        //删除商品
        List<Products> productsList = productMapper.selectListByQuery(productQW);
        if(productsList!=null)
            for(Products products : productsList){
                productsService.delete(products.getProductId());
            }

        return Result.success("删除成功");
    }

    @Override
    public Object updateStore(StoresInfo storesInfo){
        Stores stores = storesInfo.getStores();
        List<StoreServices> storesServiceList = storesInfo.getStoreServicesList();
        int[] tagList = storesInfo.getTag();

        //更新商店
        storesMapper.update(stores);

        //更新商店服务
        QueryWrapper queryWrapper1 = new QueryWrapper();
        queryWrapper1.from(STORE_SERVICES)
                .where(STORE_SERVICES.STORE_ID.eq(stores.getStoreId()));
        if(!storeServicesMapper.selectListByQuery(queryWrapper1).isEmpty())
            storeServicesMapper.deleteByQuery(queryWrapper1);
        for(StoreServices service : storesServiceList) {
            service.setStoreId(stores.getStoreId());
            storeServicesMapper.insert(service);
        }

        //更新标签
        QueryWrapper queryWrapper2 = new QueryWrapper();
        queryWrapper2.from(STORE_TAG_RELATION)
                .where(STORE_TAG_RELATION.STORE_ID.eq(stores.getStoreId()));
        if(!storeTagRelationMapper.selectListByQuery(queryWrapper2).isEmpty())
            storeTagRelationMapper.deleteByQuery(queryWrapper2);
        for(int tag : tagList){
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper
                    .from(STORE_TAG_RELATION)
                    .where(STORE_TAG_RELATION.STORE_ID.eq(stores.getStoreId()))
                    .and(STORE_TAG_RELATION.TAG_ID.eq(tag));
            StoreTagRelation storeTagRelation = storeTagRelationMapper.selectOneByQuery(queryWrapper);
            if(storeTagRelation==null) {
                StoreTagRelation newTag = new StoreTagRelation();
                newTag.setStoreId(stores.getStoreId());
                newTag.setTagId(tag);
                storeTagRelationMapper.insert(newTag);
            }
        }

        return Result.success("更新成功");
    }

    @Override
    public Object getStoreList(){
        int userId = getUserId();
        Users user = userMapper.selectOneById(userId);
        int level = Integer.parseInt(user.getMemberLevel());
        List<StoresInfo> storesInfoList = new ArrayList<>();
        QueryWrapper storesQW = new QueryWrapper();

        //查找对应商店
        if(level==-2){
            storesQW.select(STORES.ALL_COLUMNS).from(STORES).where(STORES.DELETE.eq(0));
        }
        else {
            storesQW.select(STORES.ALL_COLUMNS)
                    .from(STORES)
                    .leftJoin(STORE_FOLLOWERS).on(STORE_FOLLOWERS.STORE_ID.eq(STORES.STORE_ID))
                    .where(STORE_FOLLOWERS.USER_ID.eq(userId))
                    .and(STORES.DELETE.eq(0))
                    .groupBy(STORES.STORE_ID);
        }

        List<Stores> storesList = storesMapper.selectListByQuery(storesQW);

        for(Stores stores : storesList){
            QueryWrapper serviceQW = new QueryWrapper();
            QueryWrapper tagQW = new QueryWrapper();
            serviceQW.select()
                    .from(STORE_SERVICES)
                    .where(STORE_SERVICES.STORE_ID.eq(stores.getStoreId()));
            tagQW.select()
                    .from(STORE_TAG_RELATION)
                    .where(STORE_TAG_RELATION.STORE_ID.eq(stores.getStoreId()));

            List<StoreServices> servicesList = storeServicesMapper.selectListByQuery(serviceQW);
            List<StoreTagRelation> storeTagRelationList = storeTagRelationMapper.selectListByQuery(tagQW);

            int[] tag =new int[storeTagRelationList.size()];
            int i=0;
            for(StoreTagRelation tags : storeTagRelationList){
                tag[i] = tags.getTagId();
                i++;
            }

            StoresInfo storesInfo = new StoresInfo();
            storesInfo.setStores(stores);
            storesInfo.setStoreServicesList(servicesList);
            storesInfo.setTag(tag);
            storesInfoList.add(storesInfo);

        }
        return Result.success(storesInfoList);
    }

    @Override
    public Object getShopkeeperStats() {
        int userId = getUserId();
        ShopKeeperStatus shopKeeperStatus = new ShopKeeperStatus();
        shopKeeperStatus.setFavoriteCount(0);
        shopKeeperStatus.setShopturnover(0);
        shopKeeperStatus.setOrderCount(0);
        shopKeeperStatus.setShopNumber(0);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.select(STORE_FOLLOWERS.ALL_COLUMNS).from(STORE_FOLLOWERS)
                .where(STORE_FOLLOWERS.USER_ID.eq(userId));
        List<StoreFollowers> storeFollowersList = storeFollowersMapper.selectListByQuery(queryWrapper);
        shopKeeperStatus.setShopNumber(storeFollowersList.size());
        List<Products> productsList = new ArrayList<>();
        for (StoreFollowers storeFollowers : storeFollowersList) {
            queryWrapper = new QueryWrapper();
            queryWrapper.select(FAVORITES.ALL_COLUMNS).from(FAVORITES)
                    .where(FAVORITES.STORE_ID.eq(storeFollowers.getStoreId()));
            int l = favoritesMapper.selectListByQuery(queryWrapper).size();
            shopKeeperStatus.setFavoriteCount(shopKeeperStatus.getFavoriteCount() + l);
            queryWrapper = new QueryWrapper();
            queryWrapper.select(PRODUCTS.ALL_COLUMNS).from(PRODUCTS)
                    .where(PRODUCTS.STORE_ID.eq(storeFollowers.getStoreId()));
            productsList.addAll(productMapper.selectListByQuery(queryWrapper));
        }
        List<OrderItems> orderItems=new ArrayList<>();
        for (Products products : productsList) {
            queryWrapper = new QueryWrapper();
            queryWrapper.select(ORDER_ITEMS.ALL_COLUMNS).from(ORDER_ITEMS)
                    .where(ORDER_ITEMS.PRODUCT_ID.eq(products.getProductId()));
            orderItems.addAll(orderItemsMapper.selectListByQuery(queryWrapper));
        }
        for (OrderItems orderItems1 : orderItems) {
            Orders orders = ordersMapper.selectOneById(orderItems1.getOrderId());
            shopKeeperStatus.setShopturnover(shopKeeperStatus.getShopturnover()+orders.getTotalAmount());
        }
        orderItems=orderItems.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(OrderItems::getOrderId))),
                        ArrayList::new));
        shopKeeperStatus.setOrderCount(orderItems.size());
        return Result.success(shopKeeperStatus);
    }
}
